Skip to content

macOS12编译Swift6的步骤与问题

⚠️⚠️⚠️警告⚠️⚠️⚠️

后面的不用看,也不应该在macOS12上自行编译Swift6,因为Swift6中除了Swift编译器,很多工具如Swift Package Manager都依赖macOS13+上面的API。

在macOS12上即使将这些工具都成功编译,但在macOS12上使用也会有问题,并且只能使用Swift核心部分,如:swift,swiftc等工具。

所有直接下载Apple提供的Swift6+工具链即可,在macOS12上只使用它的swift,swiftc等工具即可。

总结:在macOS12上编译Swift6+的思路就是错的,纯纯的浪费时间,啥也不是。

使用场景

由于macOS只能升级到macOS 12.7.5,导致Xcode只能升级到Xcode 14.2;其中Swift版本为Swift 5.7.2。现在想使用Siwft 6或者
更高的版本,所有只能尝试在macOS 12.7.5(macOS Monterey)上编译Swift 6+,看是否能正常编译和正常使用。并且编译的Swift 6+
可能功能不全,只能使用swift Package Manager的方式创建应用,且可能不能使用其中与iOS,macOS,tvOS相关的SDK,或者说编译生成
的Swift 6+中的iOS 等SDK与macOS平台不匹配。并且所有自己编译的Swift版本不能上架到App Store(上架需要与Xcode绑定的Swift,
或者需要升级到最新版本的Xcode才能上架)。
总之在低版本的macOS上编译的高版本的Swift,使用时可能会有一些问题,但是编译Swift package manager(例如命令行工具)方式的程序应该没问题。

编译要求

编译Swift6+需要的Swift版本最低为5.8,有由于Xcode 14.2的Swift版本为5.7.2,所以需要安装自定义的工具链。又由于Swift 6.0+的版本在macOS 12
的系统上无法运行,最后通过测试找到了macOS 12支持的Swift的最高版本为Swift 5.10.1,所有就下载了该版本作为编译Swift 6+的编译工具链,安装自定义工具链
需要设置工具工具链的路径才能使用指定版本工具链(Xcode中可以通过Toolchains选项切换版本),设置工具链环境变量方法:

export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)

使用时可能还需要设置它的动态库地址,否者可能出现库找不到的情况,可以尝试下列配置:

export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)
export CMAKE_Swift_COMPILER=/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/bin/swiftc

需要安装:ninja sccache

brew install ninja sccache

如果sccache等工具无法安装,则可以到GitHub获取其对应的二进制文件,然后创建软连接,如下:

#!/usr/bin/env bash 

## 先移除已经存在的软连接
rm -rf /usr/local/bin/sccache

## 创建软连接
ln -s /Volumes/ExData/Downloads/dependencies/sccache/bin/sccache /usr/local/bin/sccache
echo "swift-dependencies-sccache服务创建成功!"

如果还有其他的工具无法安装时,也可以使用软连接的方式。

其它要求与配置可以查看: swiftlang

资源

⚠️编译结果注意#⚠️

由于在哪macOS12上编译Swift6存在限制,因为Swift6会使用到macOS13+上系统的库,有些工具如:SwiftPM 即使编译成功也无法使用,因为SwiftPM需要使用macOS13+上面的系统库而导致

SwiftPM在macOS12上无法使用,而还有些工具又依赖SwiftPM,所以导致这一系列工具都在macOS12上无法使用,然而编译的swift swiftc工具可以在macOS12上使用。

所以再macOS12上只编译Swift6+的核心库即可,然后直接使用swift swiftc这些工具来体验Swift6+与学习。

⚠️警告⚠️

由于系统原因swiftpmsourcekit-lsp编译不过,主要是因为这个工具再Swift6+的环境下使用了macOS13+上面的系统API,所以再编译时无法通过,即使通过多种方法,比如:
修改源码的方式,即使有可能编译通过(概率不大),那么也会有使用问题,所有最简单的办法是直接只编译Swift6的核心库即可,就可以简单的使用Swift6+的功能比如直接使用swift
swiftc 等命令编译执行简单的单个源代码文件程序。
又因为形如swiftpm工具等无法编译通过,那么Swift Package Manager相关工具就无法使用,比如:swift runswift buildswift test等命令就无法使用。
或者有更更多的工具也无法使用,或者会出现莫名其妙的问题。
总之:只需要编译Swift6+最核心的库即可,然后简单的使用swiftswiftc命令进行简单的程序测试,Swift6+语法的体验即可。

Swift 6+编译步骤

  1. 创建编译目录并进入:
mkdir swift
cd swift

因为Swift clone时会有很多同级代码仓库,所有先创建一个总目录swift方便代码管理。

  1. 从GitHub cloneSwift源代码并进入目录:
git clone https://github.com/swiftlang/swift.git
cd swift
  1. update与checkout Swift的指定版本,当前编译Swift 6.0.0,所以checkout 6.0.0的版本:
utils/update-checkout --clone --tag swift-6.0-RELEASE

⚠️注意⚠️
checkout指定版本很重要,之前由于update-checkout操作不正确,编译前update-checkout了多个版本,导致编译时出现了很多莫名奇妙的问题,而导致Swift 6+编译不通过
比如先用默认分支编译然后编译失败了,接着尝试update-checkout swift 6.2又失败了,再然后update-checkout swift 6.0还是编译失败了,并且在update-checkout时
也可能操作失误了,导致尝试了很多次结果依然失败了,而且每次编译Swift都需要号几个小时,就这样整了几天结果还失败了,真是被坑麻了。
后来尝试了从了重新拉取Swift的代码,并且update-checkout 6.0居然一次就编译过了。
✅所以✅
每次编译不同版本,或者总是编译失败,可以尝试重新clone Swift代码,然后再正确update-checkout指定版本,最后再执行编译操作,这样的编译问题可能就更少。

  1. 设置编译环境
export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)

注意:这一步必须设置才能使用使用指定版本的Swift工具链,上面的swift-latest.xctoolchain真实对应的是swift-5.10.1-RELEASE-.xctoolchain版本。

  1. 执行编译命令:
utils/build-script --skip-build-benchmarks \
  --swift-darwin-supported-archs "$(uname -m)" \
  --release-debuginfo --swift-disable-dead-stripping \
  --bootstrapping=hosttools \
  --sccache \
  --install-swift

或者使用release模式(体积更小)编译:

ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
  --swift-darwin-supported-archs "$(uname -m)" \
  --release --swift-disable-dead-stripping \
  --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
  --bootstrapping=hosttools \
  --sccache \
  --install-swift

几种编译模式,它们的体积一次减小:

--debug
--release-debuginfo
--release
--min-size-release

✅由于swiftpm,sourcekit-lsp,xctest,swiftdocc等工具无法在macOS12上编译或者正常使用,所以只需要编译Swift6核心库,然后直接使用swift swiftc等工具即可。

✅使用--release模式编译可获取较小的二进制文件,生成的XcodeDefault.xctoolchain文件大小约为3.1G。编译命令如下:

ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
  --swift-darwin-supported-archs "$(uname -m)" \
  --release --swift-disable-dead-stripping \
  --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
  --bootstrapping=hosttools \
  --sccache \
  --install-swift

✅使用--min-size-release模式编译可获取最小二进制文件,生成的XcodeDefault.xctoolchain文件大小约为2.5G。编译命令如下:

ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-MinSizeRelAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
  --swift-darwin-supported-archs "$(uname -m)" \
  --min-size-release --swift-disable-dead-stripping \
  --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
  --bootstrapping=hosttools \
  --sccache \
  --llbuild --install-llbuild \
  --swift-driver --install-swift-driver \
  --install-swift

✅如果需要编译完整的Swift,比如macOS13+上面编译(可以正常使用),可以使用下面的编译命令:

ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
  --swift-darwin-supported-archs "$(uname -m)" \
  --release --swift-disable-dead-stripping \
  --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
  --bootstrapping=hosttools \
  --sccache \
  --install-llvm --install-swift \
  --libcxx --install-libcxx \
  --lldb --install-lldb \
  --playgroundsupport --install-playgroundsupport \
  --llbuild --install-llbuild \
  --swiftpm --install-swiftpm \
  --sourcekit-lsp --install-sourcekit-lsp \
  --swiftdocc --install-swiftdocc \
  --xctest --install-xctest

这个命令基本上会把Swift常用的工具都编译出来,不过需要注意的是:

--playgroundsupport --install-playgroundsupport 
命令最好是在
--swiftpm --install-swiftpm 
命令之前构建,否则容易出现playgroundsupport构建失败的问题。

lldb 			依赖 libcxx
swiftpm 		依赖 llbuild
sourcekit-lsp 	依赖 swiftpm
swiftdocc 		依赖 swiftpm

xctest	在macOS上编译容易出错,并且不需要编译。
Swift 官方在 2024 年开始转移 XCTest 的 Darwin 构建到 系统自带的 XCTest.framework,


--sourcekit-lsp --install-sourcekit-lsp \
--swiftdocc --install-swiftdocc \
--xctest --install-xctest
命令可以移除,应为它们依赖SwiftPM,而SwiftPM运行又依赖macOS13+上面的API,所以会导致这三个命令编译不过。

最后尝试使用这些编译命令时,可以先一小部分一小部分的编译,这样更容易修补编译时出现的错误。

编译参数相关问题

  • Release(--release)模式下可能会出现SwiftMacros.DebugDescriptionMacro宏找找不到的情况:
    原因:
    Swift 编译器在 构建标准库阶段 会动态加载 SwiftMacros 宏插件(即 libSwiftMacros.dylib),路径由 -external-plugin-path 指定。例如:
    ## 示例
    -external-plugin-path /.../lib/swift/host/plugins#/.../bin/swift-plugin-server
    
    1. Dead Stripping 或 CMAKE_BUILD_TYPE=Release 会导致:
    	- CMake 不安装或不复制 host plugins;
    	- swiftc 构建时剥离 EXTERNAL_PLUGIN_PATH 相关环境;
    2. Swift 的 bootstrapping 阶段使用独立环境,插件路径不继承;
    3. swift-plugin-server 在 Release 模式有时未安装在相同层级路径。

    解决方法:
    通过--swift-cmake-options参数设置-DSWIFT_EXTERNAL_PLUGIN_PATH的值即可,示例:
    ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
    --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \

    ⚠️ 注意:路径中的 # 是分隔符,不能换成 : 或空格。
    ✅ 显式指定宏插件路径(推荐); 在执行 utils/build-script 时显式传入:
     ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
     utils/build-script --skip-build-benchmarks \
       --swift-darwin-supported-archs "$(uname -m)" \
       --release --swift-disable-dead-stripping \
       --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
       --bootstrapping=hosttools

    为什么 –release-debuginfo 可以成功? 因为它的 CMake 构建类型是:
    CMAKE_BUILD_TYPE = RelWithDebInfo

    这个模式下:
    • 保留 debug 信息;
    • 仍然开启优化;
    • 关键是 不会剥离宏插件符号和路径;
    • 所以 Swift 在编译 swiftCore 时能正确加载 SwiftMacros.

编译时需要修改的文件

  • 编译llbuildCMakeLists.txt文件中出现CMP0037错误,这是由cmake版本过高造成的。解决方法有两种:

第一种:llbuild中全局查找所有的cmake_policy(SET CMP0037 OLD)并将其注释掉即可,如下:

if(POLICY CMP0037)
  #cmake_policy(SET CMP0037 OLD)
endif(POLICY CMP0037)

第二种:降低cmake版本,可以直接重新安装低版本的cmake版本,如果不想重新安装可以下载指定版本cmake,然后编译时传入自定义cmake路径,如下:

--cmake "/Volumes/ExData/Downloads/dependencies/cmake/3.29.0/bin/cmake"
  • 编译swiftpm时出现的各种问题,其中包括:-no_warn_duplicate_librariesThrottledProgressAnimation.swiftswift-certificates/Sources/X509/PromiseAndFuture.swift错误,解决方法如下:

-no_warn_duplicate_libraries编译指令错误,的修复方法如下:

  1. 进入swiftpm源码目录
  2. 用工具搜索该仓库中所有代码中的-no_warn_duplicate_libraries
  3. 注释掉-no_warn_duplicate_libraries,如果它的前面出现-Xlinker同时注释掉,示例如下:
//linkArguments.append("-Xlinker")
//linkArguments.append("-no_warn_duplicate_libraries")

swiftpm/Sources/Basics/ProgressAnimation/ThrottledProgressAnimation.swift文件中的API不被低于macOS13.0的系统修复方法:

#if canImport(_Concurrency) && swift(>=5.7)
import _Concurrency
// 该区域为原文件中的代码内容
@available(macOS 13.0, iOS 16.0, *)
final class ThrottledProgressAnimation: ProgressAnimationProtocol {
	....
}
@available(macOS 13.0, iOS 16.0, *)
extension ProgressAnimationProtocol {
	....
}
#else
// 在老系统上禁用 throttled 功能
extension ProgressAnimationProtocol {
  public func throttled(
    interval: Double
  ) -> some ProgressAnimationProtocol {
    self
  }
}
#endif

swift-certificates/Sources/X509/PromiseAndFuture.swift文件中不被识别的_Concurrency,只需要导入_Concurrency即可:

#if canImport(_Concurrency)
import _Concurrency
#endif

//源文件内容
  • ⚠️警告⚠️: 通过修改swiftpm中的相关源码,可以编译成功,但是:即使swift package manager被编译成功的,但是它运行时依然要依赖macOS13+的系统库才能正常运行。所以再macOS12下不需要编译swiftpm,并且不能使用swift package manager的相关功能。

关于xctoolchain文件中的Info.plist文件生成

xctoolchain文件中的Info.plist文件生成,Info.plist文件用于将该工具链导入系统环境,让系统能识别swift的相关工具。

并且将该工具链导入系统的前提是需要将xxx.xctoolchain文件安装(或创建软连接)到:/Library/Developer/Toolchains/目录:

Info.plist文件内容示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Aliases</key>
	<array>
		<string>swift</string>
	</array>
	<key>CFBundleIdentifier</key>
	<string>org.swift.60020251105</string>
	<key>CompatibilityVersion</key>
	<integer>2</integer>
	<key>CompatibilityVersionDisplayString</key>
	<string>Xcode 8.0</string>
	<key>CreatedDate</key>
	<date>2025-11-05T08:08:08Z</date>
	<key>DisplayName</key>
	<string>Swift 6.0 Release 2025-11-05</string>
	<key>OverrideBuildSettings</key>
	<dict>
		<key>ENABLE_BITCODE</key>
		<string>NO</string>
		<key>OTHER_SWIFT_FLAGS</key>
		<string>$(inherited) -plugin-path $(TOOLCHAIN_DIR)/usr/lib/swift/host/plugins</string>
		<key>SWIFT_DEVELOPMENT_TOOLCHAIN</key>
		<string>YES</string>
		<key>SWIFT_DISABLE_REQUIRED_ARCLITE</key>
		<string>YES</string>
		<key>SWIFT_LINK_OBJC_RUNTIME</key>
		<string>YES</string>
		<key>SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME</key>
		<string>YES</string>
	</dict>
	<key>ReportProblemURL</key>
	<string>https://bugs.swift.org/</string>
	<key>ShortDisplayName</key>
	<string>Swift 6.0.0 Release</string>
	<key>Version</key>
	<string>6.0.20251105</string>
</dict>
</plist>

附加:设置动态链接库目录DYLD_LIBRARY_PATH

示例:

export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/lib/
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/lib/swift/macosx/